package com.tjvib.view.activity;

import static com.tjvib.Constants.PARAM_ACCX;
import static com.tjvib.Constants.PARAM_ACCY;
import static com.tjvib.Constants.PARAM_ACCZ;
import static com.tjvib.Constants.PARAM_ALL;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.TextView;

import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.LegendRenderer;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.DataPointInterface;
import com.jjoe64.graphview.series.LineGraphSeries;
import com.jjoe64.graphview.series.OnDataPointTapListener;
import com.jjoe64.graphview.series.PointsGraphSeries;
import com.jjoe64.graphview.series.Series;
import com.tjvib.Constants;
import com.tjvib.R;
import com.tjvib.base.BaseActivity;
import com.tjvib.util.LogUtil;
import com.tjvib.util.Manager.DataSetManager;
import com.tjvib.math.Complex;
import com.tjvib.math.FFT;
import com.tjvib.presenter.BasePresenter;
import com.tjvib.sensor.SensorData;
import com.tjvib.util.Manager.AppManager;
import com.tjvib.util.Manager.UserManager;
import com.tjvib.util.PoiUtil;
import com.tjvib.util.PressUtil;
import com.tjvib.util.ToastUtil;
import com.tjvib.view.dialog.LoadingDialog;
import com.tjvib.widget.TitleLayout;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FftActivity extends BaseActivity {

    private TextView fft_tv_x, fft_tv_y;
    private GraphView fft_gv_data;
    private Spinner fft_sp_sensor;
    private RadioButton fft_rb_all, fft_rb_accx, fft_rb_accy, fft_rb_accz;
    private Button fft_btn_export;
    private TitleLayout fft_tit;

    private String sensorSelect = "";
    private LineGraphSeries<DataPoint> mSeries1 = new LineGraphSeries<>(),
            mSeries2 = new LineGraphSeries<>(),
            mSeries3 = new LineGraphSeries<>();

    private PointsGraphSeries<DataPoint> pSeries = new PointsGraphSeries<>();
    private DataPoint[] dataPointsX, dataPointsY, dataPointsZ;
    private static int curSelectedParm = PARAM_ALL;

    private OnDataPointTapListener onDataPointTapListenerForFFT = new OnDataPointTapListener() {
        @Override
        public void onTap(Series series, DataPointInterface dataPoint) {
            switch (curSelectedParm){
                case PARAM_ACCX:
                    fft_tv_y.setText("AccX=" + dataPoint.getY());
                    break;
                case PARAM_ACCY:
                    fft_tv_y.setText("AccY=" + dataPoint.getY());
                    break;
                case PARAM_ACCZ:
                    fft_tv_y.setText("AccZ=" + dataPoint.getY());
                    break;
                case PARAM_ALL:
                    double x = 0, y = 0, z = 0;
                    for(int i = 0; i < dataPointsX.length; i++){
                        if(dataPointsX[i].getX() == dataPoint.getX()){
                            x = dataPointsX[i].getY();
                            break;
                        }
                    }
                    for(int i = 0; i < dataPointsY.length; i++){
                        if(dataPointsY[i].getX() == dataPoint.getX()){
                            y = dataPointsY[i].getY();
                            break;
                        }
                    }
                    for(int i = 0; i < dataPointsZ.length; i++){
                        if(dataPointsZ[i].getX() == dataPoint.getX()){
                            z = dataPointsZ[i].getY();
                            break;
                        }
                    }
                    fft_tv_y.setText("AccX=" + x + "\nAccY=" + y +"\nAccZ=" + z);
                    break;
            }

            fft_tv_x.setText("" + dataPoint.getX());
            pSeries.resetData(new DataPoint[]{
                    new DataPoint(dataPoint.getX(), dataPoint.getY())
            });
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected int initLayout() {
        return R.layout.activity_fft;
    }

    @Override
    protected boolean initView() {
        fft_gv_data = findViewById(R.id.fft_gv_data);

        fft_sp_sensor = findViewById(R.id.fft_sp_sensor);

        fft_tit = findViewById(R.id.fft_tit);
        fft_tit.setTitle(getIntent().getStringExtra("METHOD"));

        fft_btn_export = findViewById(R.id.fft_btn_export);
        fft_btn_export.setOnClickListener(v->{
                FileReadWriteTask fileReadWriteTask = new FileReadWriteTask();
                fileReadWriteTask.execute();
        });

        fft_rb_all = findViewById(R.id.fft_rb_all);
        fft_rb_accx = findViewById(R.id.fft_rb_accx);
        fft_rb_accy = findViewById(R.id.fft_rb_accy);
        fft_rb_accz = findViewById(R.id.fft_rb_accz);
        fft_rb_all.setOnCheckedChangeListener((compoundButton, b) -> {
            if (b) onAxisChange(PARAM_ALL);
        });
        fft_rb_accx.setOnCheckedChangeListener((compoundButton, b) -> {
            if (b) onAxisChange(PARAM_ACCX);
        });
        fft_rb_accy.setOnCheckedChangeListener((compoundButton, b) -> {
            if (b) onAxisChange(PARAM_ACCY);
        });
        fft_rb_accz.setOnCheckedChangeListener((compoundButton, b) -> {
            if (b) onAxisChange(PARAM_ACCZ);
        });

        fft_tv_x = findViewById(R.id.fft_tv_x);
        fft_tv_y = findViewById(R.id.fft_tv_y);
        return true;
    }

    @Override
    protected boolean initData() {
        List<String> sensorList = DataSetManager.getInstance().getSensorList();
        SpinnerAdapter spinnerAdapter = new ArrayAdapter<>(this, R.layout.item_spinner_dropdown, sensorList);
        fft_sp_sensor.setAdapter(spinnerAdapter);
        fft_sp_sensor.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                sensorSelect = sensorList.get(position);
                drawGraph();
                fft_rb_all.setChecked(true);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });

        return true;
    }


    @Override
    protected BasePresenter genPresenter() {
        return null;
    }


    private void drawGraph() {
        runOnUiThread(() -> {
            pSeries.setShape(PointsGraphSeries.Shape.POINT);
            fft_gv_data.getViewport().setMinX(0);
            fft_gv_data.getViewport().setScrollable(true);
            fft_gv_data.getViewport().setScalable(true);
            mSeries1.setThickness(3);
            mSeries2.setThickness(3);
            mSeries3.setThickness(3);
            pSeries.setSize(10);
            pSeries.setColor(Color.BLACK);
            mSeries1.setColor(Color.BLUE);
            mSeries2.setColor(Color.GREEN);
            mSeries3.setColor(Color.RED);
            fft_gv_data.setBackgroundColor(Color.WHITE);
            mSeries1.setTitle("AccX");
            mSeries2.setTitle("AccY");
            mSeries3.setTitle("AccZ");
            pSeries.setTitle("Clicked");
            mSeries1.setOnDataPointTapListener(onDataPointTapListenerForFFT);
            mSeries2.setOnDataPointTapListener(onDataPointTapListenerForFFT);
            mSeries3.setOnDataPointTapListener(onDataPointTapListenerForFFT);
            fft_gv_data.getLegendRenderer().setBackgroundColor(Color.TRANSPARENT);
            fft_gv_data.getLegendRenderer().setVisible(true);
            fft_gv_data.getLegendRenderer().setTextSize(18);
            fft_gv_data.getLegendRenderer().setTextColor(R.color.main_grey_2);
            fft_gv_data.getLegendRenderer().setAlign(LegendRenderer.LegendAlign.TOP);
            fft_gv_data.getGridLabelRenderer().setHorizontalAxisTitle("频率(Hz)");
            fft_gv_data.getGridLabelRenderer().setVerticalAxisTitle("幅值(g)");
            fft_gv_data.getGridLabelRenderer().setHorizontalAxisTitleTextSize(24);
            fft_gv_data.getGridLabelRenderer().setVerticalAxisTitleTextSize(24);
            fft_gv_data.addSeries(mSeries1);
            fft_gv_data.addSeries(mSeries2);
            fft_gv_data.addSeries(mSeries3);
            fft_gv_data.addSeries(pSeries);

            initGraphViewForFFT();
        });
    }


    private void initGraphViewForFFT() {
        runOnUiThread(() -> {
            mSeries1.resetData(new DataPoint[]{});
            mSeries2.resetData(new DataPoint[]{});
            mSeries3.resetData(new DataPoint[]{});
            pSeries.resetData(new DataPoint[]{});

            double len, f0;
            int cutSize;
            List<? extends SensorData> dataList;

            if (sensorSelect.equals("local")) {
                dataList = DataSetManager.getInstance().getDataSetContent(-1);
            } else {
                dataList = DataSetManager.getInstance().getDataSetContent(Integer.parseInt(sensorSelect));
            }

            cutSize = dataList.size();
            while ((cutSize & (cutSize - 1)) != 0) {
                cutSize--;
            }

//        if (cutSize < 50) {
//            fft_gv_data.getViewport().setMinX(0d);
//            fft_gv_data.getViewport().setMaxX(cutSize);
//        }

            double startTime = dataList.get(1).timestamp;
            double endTime = dataList.get(cutSize - 1).timestamp;
            double dt = (endTime - startTime) / (cutSize - 1);
            double fs = 1.0 / dt;

            Complex[] complex_accx0 = new Complex[cutSize];
            Complex[] complex_accy0 = new Complex[cutSize];
            Complex[] complex_accz0 = new Complex[cutSize];

            for (int i = 0; i < cutSize; i++) {
                complex_accx0[i] = new Complex(dataList.get(i).acc[0], 0D);
                complex_accy0[i] = new Complex(dataList.get(i).acc[1], 0D);
                complex_accz0[i] = new Complex(dataList.get(i).acc[2], 0D);
            }

            double N = cutSize;
            //double fs = 100;//采样频率
            //double dt = 1/fs;//采样间隔
            double time = N / fs;
            f0 = 1 / (dt * N);
            len = Math.ceil((N - 1) / 2);
            fft_gv_data.getViewport().setMaxX(len*f0);

            Complex[] complex_accx = FFT.fft(complex_accx0);
            Complex[] complex_accy = FFT.fft(complex_accy0);
            Complex[] complex_accz = FFT.fft(complex_accz0);

            dataPointsX = new DataPoint[(int) len + 1];
            dataPointsY = new DataPoint[(int) len + 1];
            dataPointsZ = new DataPoint[(int) len + 1];

            double dpxh, dpyh, dpzh;
            for (int i = 0; i <= len; i++) {
                dpxh = Math.sqrt(complex_accx[i].re() * complex_accx[i].re() + complex_accx[i].im() * complex_accx[i].im());
                dataPointsX[i] = new DataPoint(i * f0, dpxh);

                dpyh = Math.sqrt(complex_accy[i].re() * complex_accy[i].re() + complex_accy[i].im() * complex_accy[i].im());
                dataPointsY[i] = new DataPoint(i * f0, dpyh);

                dpzh = Math.sqrt(complex_accz[i].re() * complex_accz[i].re() + complex_accz[i].im() * complex_accz[i].im());
                dataPointsZ[i] = new DataPoint(i * f0, dpzh);

                mSeries1.appendData(dataPointsX[i], true, 1000);
                mSeries2.appendData(dataPointsY[i], true, 1000);
                mSeries3.appendData(dataPointsZ[i], true, 1000);
            }
            pSeries.resetData(new DataPoint[]{
                    new DataPoint(dataPointsX[0].getX(), dataPointsX[0].getY())
            });
        });
    }


    private void onAxisChange(int axis) {
        curSelectedParm = axis;
        fft_gv_data.removeAllSeries();
        fft_gv_data.addSeries(pSeries);
        switch (axis) {
            case PARAM_ACCX:
                fft_gv_data.removeAllSeries();
                fft_gv_data.addSeries(mSeries1);
                mSeries1.resetData(dataPointsX);
                break;
            case PARAM_ACCY:
                fft_gv_data.removeAllSeries();
                fft_gv_data.addSeries(mSeries2);
                mSeries2.resetData(dataPointsY);
                break;
            case PARAM_ACCZ:
                fft_gv_data.removeAllSeries();
                fft_gv_data.addSeries(mSeries3);
                mSeries3.resetData(dataPointsZ);
                break;
            case PARAM_ALL:
                fft_gv_data.removeAllSeries();
                fft_gv_data.addSeries(mSeries1);
                mSeries1.resetData(dataPointsX);
                fft_gv_data.addSeries(mSeries2);
                mSeries2.resetData(dataPointsY);
                fft_gv_data.addSeries(mSeries3);
                mSeries3.resetData(dataPointsZ);
        }
    }

    private class FileReadWriteTask extends AsyncTask<Void, Void, Void> {
        private LoadingDialog loadingDialog = null;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            loadingDialog = new LoadingDialog(FftActivity.this);
            loadingDialog.showDialog(FftActivity.this, "正在输出报告...", 5);
        }

        @Override
        protected Void doInBackground(Void... voids) {
            SimpleDateFormat sdf = new SimpleDateFormat();
            sdf.applyPattern("yyyy-MM-dd HH:mm:ss");
            Date date = new Date();

            Map<String, String> replacements = new HashMap<>();
            replacements.put("【时间】", sdf.format(date));
            replacements.put("【姓名】", UserManager.getInstance().getUsername());
            replacements.put("【传感器】", fft_sp_sensor.getSelectedItem().toString().trim());
            replacements.put("【频率】", fft_tv_x.getText().toString().trim());
            replacements.put("【幅值】", fft_tv_y.getText().toString().trim());
            Bitmap bitmap = PoiUtil.loadBitmapFromView(fft_gv_data);

            synchronized (PoiUtil.class) {
                PoiUtil.replaceFieldsWithImage(bitmap, FftActivity.this, Constants.METHOD_FFT,
                        sdf.format(date) + ".docx", replacements);
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void unused) {
            super.onPostExecute(unused);
            if(loadingDialog != null) loadingDialog.dismiss();
            ToastUtil.show("报告已保存");
        }
    }
}